package com.cskaoyan.search.service.impl;

import com.cskaoyan.mall.commons.exception.BizException;
import com.cskaoyan.mall.dto.ProductDto;
import com.cskaoyan.search.consts.SearchRetCode;
import com.cskaoyan.search.converter.ProductConverter;
import com.cskaoyan.search.dto.SearchResponse;
import com.cskaoyan.search.dto.SearchTitleResponse;
import com.cskaoyan.search.entity.ItemDocument;
import com.cskaoyan.search.form.SearchRequest;
import com.cskaoyan.search.repository.ProductRepository;
import com.cskaoyan.search.service.ProductSearchService;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * @Aurhor: 帅的一批
 * @CreateAt: 2022/11/1 22:58
 * @Description:
 * @PACKAGE_NAME： com.cskaoyan.search.service.impl
 */
@Service
public class ProductSearchServiceImpl implements ProductSearchService {


    @Autowired
    ElasticsearchRestTemplate restTemplate;

    @Autowired
    ProductRepository productRepository;

    @Autowired
    ProductConverter productConverter;


    @Override
    public SearchResponse search(SearchRequest request) {
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //获取bool查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", request.getKey());
//        WildcardQueryBuilder wildcardQuery = QueryBuilders.wildcardQuery("title", "*" + request.getKey() + "*");

//        QueryStringQueryBuilder queryStringQuery = QueryBuilders.queryStringQuery("title");
//        queryStringQuery.field("title").field("sellPoin");
//        queryStringQuery.queryName(request.getKey());

//        HashMap<String, Float> stringDoubleHashMap = new HashMap<>();
//        stringDoubleHashMap.put("title",100F);
//        stringDoubleHashMap.put("sellPoint", 900f);
//        QueryStringQueryBuilder queryStringQuery = QueryBuilders.queryStringQuery(request.getKey());
//        queryStringQuery.fields(stringDoubleHashMap);
        boolQueryBuilder.must(matchQueryBuilder);
        queryBuilder.withQuery(boolQueryBuilder);
        //增加分页

        Sort sort = null;
        //判断是否需要排序
        if (!StringUtils.isEmpty(request.getSort())) {
            //需要从低到高排序
            if ("1".equals(request.getSort())) {
                sort = Sort.by(Sort.Direction.ASC, "price");
            } else if ("-1".equals(request.getSort())) {
                //价格又高到低
                sort = Sort.by(Sort.Direction.DESC, "price");
            }
        }
        //添加排序
        PageRequest of = null;
        if (sort == null) {
            of = PageRequest.of(request.getPage() - 1, request.getSize());
        } else {
            of = PageRequest.of(request.getPage() - 1, request.getSize(), sort);
        }

        queryBuilder.withPageable(of);

        //查看是否需要对价格区间排序
        // 构造bool查询中的范围查询
        RangeQueryBuilder priceRange = QueryBuilders.rangeQuery("price");
        if (request.getPriceGt() != null) {
            priceRange.gte(request.getPriceGt());
        }
        if (request.getPriceLte() != null) {
            priceRange.lte(request.getPriceLte());
        }
        // 将范围查询添加到bool查询的filter中
        boolQueryBuilder.filter(priceRange);

        // 将bool查询添加到NativeSearchQueryBuilder
        queryBuilder.withQuery(boolQueryBuilder);

        // 构造高亮参数
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title").preTags("<font color='red'>").postTags("</font>");
        // 向NativeSearchQueryBuilder添加高亮参数
        queryBuilder.withHighlightBuilder(highlightBuilder);
        //queryBuilder.withSort(new ScoreSortBuilder());

        // 使用ElasticsearchRestTemplate发起搜索请求
        NativeSearchQuery build = queryBuilder.build();
        SearchHits<ItemDocument> search = restTemplate.search(build, ItemDocument.class);

        // 获取满足条件的总文档数量
        long totalHits = search.getTotalHits();

        // 获取包含所有命中文档的SearchHit对象
        List<SearchHit<ItemDocument>> searchHits = search.getSearchHits();

        ArrayList<ItemDocument> itemDocuments = new ArrayList<>();

        // 处理搜索到的结果集即SearchHit<ItemDocument>集合
        searchHits.forEach(hit -> {
            // 获取命中的文档
            ItemDocument content = hit.getContent();

            //获取高亮字段
            List<String> title = hit.getHighlightField("title");

            // 用高亮字段替换
            content.setTitle(title.get(0));

            itemDocuments.add(content);
        });
        List<ProductDto> productDtos = productConverter.items2Dto(itemDocuments);
        return new SearchResponse(totalHits, productDtos);

    }

    @Override
    public SearchResponse fuzzySearch(SearchRequest request) {
//        if (request.getKey().contains("*")){
//            throw new BizException(SearchRetCode.FAIL.getCode(),
//                    SearchRetCode.FAIL.getMsg());
//        }

        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 获取bool查询Builder
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //构建模糊查询
//        WildcardQueryBuilder wildcardQuery = QueryBuilders.wildcardQuery("title", "*" + request.getKey() + "*");
        // 构造bool查询中match查询
        MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("title", request.getKey());
        // 将该查询加入bool查询must中
        boolQueryBuilder.must(matchQuery);

        queryBuilder.withQuery(boolQueryBuilder);

        // 构造分页参数
        //PageRequest price = PageRequest.of(0, 10, Sort.by(Sort.Order.desc("price")));
        PageRequest price = PageRequest.of(request.getPage(), request.getSize());
        // 向NativeSearchQueryBuilder添加分页参数
        queryBuilder.withPageable(price);


        //queryBuilder.withSort(new ScoreSortBuilder());

        // 使用ElasticsearchRestTemplate发起搜索请求
        NativeSearchQuery build = queryBuilder.build();
        SearchHits<ItemDocument> search = restTemplate.search(build, ItemDocument.class);

        // 获取满足条件的总文档数量
        long totalHits = search.getTotalHits();

        // 获取包含所有命中文档的SearchHit对象
        List<SearchHit<ItemDocument>> searchHits = search.getSearchHits();
        ArrayList<SearchTitleResponse> searchTitleResponses = new ArrayList<>();
        // 处理搜索到的结果集即SearchHit<ItemDocument>集合
        searchHits.forEach(hit -> {
            // 获取命中的文档
            ItemDocument content = hit.getContent();
            SearchTitleResponse searchTitleResponse = new SearchTitleResponse(
                    content.getId().intValue(),
                    content.getPrice(),
                    content.getTitle(),
                    null,
                    content.getImage()
            );
            searchTitleResponses.add(searchTitleResponse);
        });

        return new SearchResponse(totalHits, searchTitleResponses);
    }
}
